"""
    本脚本用于查找precise_compilation.json中缺少的仓对应的目标(仅适配acts仓)
"""
import re
import os
import json
import xml.etree.ElementTree as ET

# 指定要遍历的路径
HOME = os.path.dirname(os.path.dirname(os.path.dirname(
    os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))))

MANIFEST_HOME = os.path.join(HOME, ".repo", "manifests")

ACTS_HOME = os.path.join(HOME, "test", "xts", "acts")

JSON_FILE = os.path.join(HOME, "test", "xts", "tools", "config", "precise_compilation.json")

TEMPLATE_LIST = [
    "ohos_moduletest_suite",
    "ohos_js_hap_suite",
    "ohos_js_app_suite",
    "ohos_shell_app_suite",
    "ohos_hap_assist_suite",
    "ohos_app_assist_suite",
    "ohos_sh_assist_suite",
    "group"
]

MISSING_JSON_FILE_PATH = "./missing.json"
NO_TARGET_JSON_PATH = "./no_target.json"

# 遍历路径下所有bundle.json,获取 路径-bundlename对应的map
def get_PathBundle_map(path):
    path_name_map = {}
    error_path = []
    # 遍历路径下的所有文件
    for root, dirs, files in os.walk(path):
        if "lite" in root:
            continue
        for file in files:
            if file == 'bundle.json':
                # 打开并读取 JSON 文件
                file_path = os.path.join(root, file)
                with open(file_path, 'r') as json_file:
                    try:
                        data = json.load(json_file)
                        # 尝试获取 "component" 对象里的 "name" 字段
                        component = data.get("component")
                        if component and isinstance(component, dict):
                            component_name = component.get("name")
                            # 如果找到了 "name" 字段，则将其添加到映射中
                            if component_name:
                                path_name_map[os.path.relpath(root,HOME)] = component_name
                    except json.JSONDecodeError as e:
                        error_path.append(root)
    return path_name_map, error_path

# 遍历manifest,获取 路径-repo对应的map
def get_PathRepo_map_impl (manifest_home, path_repo_map):
    # print(manifest_home)
    # 遍历XML文件内容
    manifest_xml_list = [manifest_home]
    for xml in manifest_xml_list:
        root = ET.parse(xml).getroot()
        if root.find('include') is not None:
            # print ("in include")
            for child in root.findall('include'):
                get_PathRepo_map_impl(os.path.join(MANIFEST_HOME, child.attrib['name']), path_repo_map)
        else:
            # print ("in else")
            for child in ET.parse(xml).getroot().findall('project'):
                if "lite" in child.attrib['path']:
                    continue
                path_repo_map[child.attrib['path']] = child.attrib['name']

def get_PathRepo_map (manifest_home):
    path_repo_map = {}
    get_PathRepo_map_impl(manifest_home, path_repo_map)
    return path_repo_map

# map转化
def changeMap(path_bundle_map, path_repo_map):
    # 创建一个新的 map 来存储 repo 到 bundle 的映射
    repo_bundle_map = {}

    path_list = []
    # 遍历 path_bundle_map 和 path_repo_map 来构建 repo_bundle_map
    for path in path_bundle_map:
        if path in path_repo_map:
            repo_bundle_map[path_repo_map[path]] = path_bundle_map[path]
            path_list.append(path)
    for path in path_list:
        del path_bundle_map[path]
        del path_repo_map[path]

    return repo_bundle_map,path_bundle_map,path_repo_map

def readjson(json_file):
    json_map = {}
    with open(json_file, 'r', encoding='utf-8') as file:
        # 读取文件内容，并将其转换成JSON对象
        json_data = json.load(file)

    for item in json_data :
        json_map[item["name"]] = item["buildTarget"]

    return json_map

def getMissing(repo_bundle_map, json_repo_target_map):
    missing_repo_bundle = {}
    for repo in repo_bundle_map:
        if repo in json_repo_target_map:
            continue
        missing_repo_bundle[repo] = repo_bundle_map[repo]
    return missing_repo_bundle



def getPathsByBundle(bundle, acts_home):
    matching_files = []
    # 遍历根目录及其子目录
    for root, dirs, files in os.walk(acts_home):
        if "lite" in root:
            continue
        for file in files:
            if file == 'BUILD.gn':
                file_path = os.path.join(root, file)
                # 读取文件内容
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                    # 检查是否包含bundle
                    if bundle in content:
                        matching_files.append(file_path)

    return matching_files

def getTargetFromBuild(build_File):
    pattern = re.compile(r'(\b(?:' + '|'.join(re.escape(word) for word in TEMPLATE_LIST) + r')\b)\("([^"]*)"\)')
    with open(build_File, 'r', encoding='utf-8') as file:
        content = file.read()
    matches = pattern.findall(content)
    # print(build_File)
    # print(matches)
    targets = [match[1] for match in matches]
    if len(targets) == 0:
        return None
    if len(targets) == 1:
        return targets[0]
    else:
        # print(f"@@@@@@@@@@@@@@@@@@@@@@@:{build_File}")
        return targets[0]

def find_build_gn(start_dir):
    current_dir = start_dir
    while current_dir.count(os.path.sep) >7:
        # 检查当前目录下是否存在BUILD.gn文件
        build_gn_path = os.path.join(current_dir, 'BUILD.gn')
        if os.path.isfile(build_gn_path):
            return build_gn_path
        # 如果当前目录没有BUILD.gn文件，则向上一级目录查找
        parent_dir = os.path.dirname(current_dir)
        if parent_dir == current_dir:
            # 已经到达根目录，跳出循环
            break
        current_dir = parent_dir
    # 没有找到BUILD.gn文件，返回None
    print(current_dir)
    return None

def getTargetfromPath(common_path):
    build_file = find_build_gn(common_path)
    if build_file == None:
        return None
    target = getTargetFromBuild(build_file)
    if target == None:
        return getTargetfromPath(os.path.dirname(os.path.dirname(build_file)))
    return target

def getMissingTarget(missing_repo_bundle,acts_home):
    missing_repo_target = {}
    no_target_repo_bundle = {}
    for repo in missing_repo_bundle:
        bundle = missing_repo_bundle[repo]
        paths = getPathsByBundle(bundle,acts_home)
        if len(paths) !=0:
            common_path = os.path.commonpath(paths)
            target = getTargetfromPath(common_path)
            missing_repo_target[repo] = target
        else:
            no_target_repo_bundle[repo] = missing_repo_bundle[repo]
    return missing_repo_target, no_target_repo_bundle

def writejson(missing_repo_target, json_file_path):
    # 创建一个新的列表来存储转换后的字典
    formatted_list = []

    # 遍历原始的map，并构建新的字典列表
    for key, value in missing_repo_target.items():
        formatted_list.append({
            'name': key,
            'buildTarget': value
        })


    # 将格式化后的列表序列化为JSON格式，并写入文件
    with open(json_file_path, 'w', encoding='utf-8') as json_file:
        json.dump(formatted_list, json_file, ensure_ascii=False, indent=4)

if __name__ == '__main__':
    #遍历路径下所有bundle.json,获取 路径-bundlename对应的map
    path_bundle_map, error_path = get_PathBundle_map(HOME)
    print(f"path_bundle_map: {len(path_bundle_map)}")
    # 遍历manifest,获取 路径-repo对应的map
    path_repo_map = get_PathRepo_map(os.path.join(os.path.dirname(MANIFEST_HOME),"manifest.xml"))
    print(f"path_repo_map: {len(path_repo_map)}")
    # map转化
    repo_bundle_map, path_bundle_map, path_repo_map = changeMap(path_bundle_map, path_repo_map)
    print(f"repo_bundle_map: {len(repo_bundle_map)}")
    # @@@@@@@@@@@@@@@@@@对应有问题的@@@@@@@@@@@@@@@@@@@@@
    print(f"path_bundle_map: {len(path_bundle_map)}")
    print(f"path_repo_map: {len(path_repo_map)}")
    # @@@@@@@@@@@@@@@@@@对应有问题的@@@@@@@@@@@@@@@@@@@@@
    # json已配置的repo_bundle
    json_repo_target_map = readjson(JSON_FILE)
    print(f"json_repo_target_map: {len(json_repo_target_map)}")
    # json中缺少的repo
    missing_repo_bundle = getMissing(repo_bundle_map, json_repo_target_map)
    print (f"missing_repo_bundle: {len(missing_repo_bundle)}")
    # 获取missing中的对应关系
    missing_repo_target, no_target_repo_bundle = getMissingTarget(missing_repo_bundle,ACTS_HOME)
    print(f"missing_repo_target: {len(missing_repo_target)}")
    print(f"no_target_repo_bundle: {len(no_target_repo_bundle)}")

    writejson(missing_repo_target, MISSING_JSON_FILE_PATH)
    writejson(no_target_repo_bundle, NO_TARGET_JSON_PATH)

    # MISSING_JSON_FILE_PATH = "./missing.json"
    # NO_TARGET_JSON_PATH = "./no_target.json"